<?php
	
	//Poorly commented.
	//TODO: comment better.
	
	//based on search from 
	//http://www.iamcal.com/publish/articles/php/search/
	//expanded to make sense and add functionality (such as ranking, more options, etc)
	
	function search_split_terms($terms){
		$terms = preg_replace("/[^A-z0-9, \"]/", '', $terms);

		$terms = preg_replace("/\"(.*?)\"/e", "search_transform_term('\$1')", $terms);
		$terms = preg_split("/\s+|,/", $terms);

		$out = array();

		foreach($terms as $term){

			$term = preg_replace("/\{WHITESPACE-([0-9]+)\}/e", "chr(\$1)", $term);
			$term = preg_replace("/\{COMMA\}/", ",", $term);

			$out[] = $term;
		}

		return $out;
	}

	function search_transform_term($term){
		$term = preg_replace("/(\s)/e", "'{WHITESPACE-'.ord('\$1').'}'", $term);
		$term = preg_replace("/,/", "{COMMA}", $term);
		return $term;
	}

	function search_escape_rlike($string){
		return preg_replace("/([.\[\]*^\$])/", '\\\$1', $string);
	}

	function search_db_escape_terms($terms){
		$out = array();
		foreach($terms as $term){
			$out[] = '[[:<:]]'.AddSlashes(search_escape_rlike($term)).'[[:>:]]';
			$out[] = AddSlashes(search_escape_rlike($term));
		}
		return $out;
	}

	function JACKED_search($terms, $exact, $table, $field, $link, $alive){
	
		if(!$exact)
			$terms = strtolower($terms);
		$terms = preg_replace('/[^0-9 a-z]/', ' ', $terms);
		$terms = trim($terms);
		$words = explode(" ", $terms);
		$terms = search_split_terms($terms);
		$terms_rx = search_rx_escape_terms($terms);
		$terms_db = search_db_escape_terms($terms);

		$parts = array();
		foreach($terms_db as $term_db){
			$parts[] = $field . " RLIKE '$term_db'";
		}
		
		if($exact)
			$parts = implode(" AND ", $parts);
		else
			$parts = implode(" OR ", $parts);

		$sql = "SELECT * FROM " . $table . " WHERE ($parts";
		
		if($alive)
			$sql .= ") AND aliveFlag = 1";

		if(JACKED_DEBUG)
			echo "<br />Using MySQL link $link, Querying... <b>$sql</b> ...<br />";

		$rows = array();

		$result = mysql_query($sql, $link);
		
		if(JACKED_DEBUG)
			echo "<br />Query results now being parsed for relevancy points (defined by JACKED_CORE_SEARCH_RELEVANCY):<br />";
		
		while($row = mysql_fetch_array($result)){
			$row = JACKED_searchDoRanking($row, $words, $terms_rx, $exact, $field);

			if($row[keywords] > 0 || $row[inkeywords] > 0){
				$rows[] = $row;
			}else{
				if(JACKED_DEBUG)
					echo '<br /><font color="red">discarded due to lack of keywords.</font><br />';
			}
		}

		uasort($rows, 'JACKED_search_sort_results');

		return $rows;
	}

	function JACKED_searchDoRanking($row, $words, $terms_rx, $exact, $field){
			//we're going to keep track of counts on all these things for each result
			////but it starts at 0
			$row[score] = 0;
			$row[keywords] = 0;
			$row[inkeywords] = 0;
			$row[stopwords] = 0;
			
			//messages that are both cute and informative (DEBUGGING!)
			////if verbose mode is on
			if(JACKED_DEBUG)
				echo "<br />checking result[0] '" . $row[0] . "' for relevancy...";
				
			
			//grab the result string that we're ranking in a variable that we can mess with safely
			$aResult = $row[$field];
			if(!$exact)
				$aResult = strtolower($aResult);
			
			//as long as we're not in exact mode, change everything to lowercase
			////for case-insensitive matching
			
			foreach($terms_rx as $term_rx){
				$hits = 0;
				if(JACKED_DEBUG)
					echo '<br> Searching exact matches for ' . $term_rx . ' in ' . $aResult . ': <br>';
				if(preg_match("/$term_rx/i", JACKED_STOPWORDS)){
					if(JACKED_DEBUG)
						echo ' [this is a stopword]';

					$hits = preg_match_all("/$term_rx/i", $aResult, $null);
					if($hits){
						$aResult = preg_replace("/$term_rx/i", ' ', $aResult);
						$row[score] += 3 * $hits;
						$row[stopwords] += $hits;
					}
					
					if(JACKED_DEBUG)
							echo "[+ 3 x " . $hits . " = " . 3 * $hits . "] ";
				}else{
					$hits = preg_match_all("/$term_rx/i", $aResult, $null);
					if($hits){
						$aResult = preg_replace("/$term_rx/i", ' ', $aResult);
						$row[score] += 10 * $hits;
						$row[keywords] += $hits;
					}
					if(JACKED_DEBUG)
						echo "[+ 10 x " . $hits . " = " . 10 * $hits . "] ";
				}
			}
			if(!$exact){
				foreach($words as $word){
					$word = preg_replace('/[^0-9 a-z]/', ' ', $word);
					if($word != '?' && !preg_match("/$word/i", JACKED_STOPWORDS)){
						if(JACKED_DEBUG)
							echo '<br> Searching partial matches for `<font color="green">' . $word . '</font>` in "<font color="yellow">' . $aResult . '</font>": <br>';
						$hits = 0;
						$findthis = explode(" ", $aResult);
						foreach($findthis as $searchTerm){
							$searchTerm = strtolower($searchTerm);
							if(strstr($searchTerm, $word)){
								$hits++;
							}
						}
						$row[score] += 5 * $hits;
						$row[inkeywords] += $hits;
						if(JACKED_DEBUG)
							echo "[+ 5 x " . $hits . " = " . 5 * $hits . "] ";	
					}else{
						if(JACKED_DEBUG)
							echo '<br> NOT Searching partial matches for `<font color="green">' . $word . '</font>` because it is a stopword.": <br>';
					}
				}
			}
			
			if(JACKED_DEBUG){
				echo "<br />total keywords: " . $row[keywords] . "<br />";
				echo "total partial keywords: " . $row[inkeywords] . "<br />";
				echo "total stopwords: " . $row[stopwords];
				echo "<br />total points assigned: " . $row['score'] . "<br />";
			}
			
			return $row;
	}

	function search_rx_escape_terms($terms){
		$out = array();
		foreach($terms as $term){
			$out[] = '\b'.preg_quote($term, '/').'\b';
		}
		return $out;
	}

	function JACKED_search_sort_results($a, $b){

		$ax = $a[score];
		$bx = $b[score];

		if ($ax == $bx){ return 0; }
		return ($ax > $bx) ? -1 : 1;
	}

	function search_html_escape_terms($terms){
		$out = array();

		foreach($terms as $term){
			if (preg_match("/\s|,/", $term)){
				$out[] = '"'.HtmlSpecialChars($term).'"';
			}else{
				$out[] = HtmlSpecialChars($term);
			}
		}

		return $out;	
	}

	function search_pretty_terms($terms_html){

		if (count($terms_html) == 1){
			return array_pop($terms_html);
		}

		$last = array_pop($terms_html);

		return implode(', ', $terms_html)." and $last";
	}

	function JACKED_search_formatted($terms, $exact, $table, $field, $link, $alive){
		$now = microtime(true);

		$results = JACKED_search($terms, $exact, $table, $field, $link, $alive);
		$term_list = search_pretty_terms(search_html_escape_terms(search_split_terms($terms)));
		
		echo "<h2>Formatted Search Results</h2>";
		
		echo "<h3>Searched term list:</h3>";
		echo $term_list . "<br />";
		
		if(count($results)){
			echo "<h3>Search Results:</h3>";
			$count = 1;
			foreach($results as $ares){
				echo "<br />result $count <br />";
				$count++;
				foreach($ares as $field => $val){
					if(!is_numeric($field))
						echo "$field: $val <br />";
				}
			}
			
		}else{
			echo '<h3>we ain\'t found <b>nothin\'</b></h3>.';
			
		}
		
		$totalTime = (microtime(true) - $now);
		echo '<h2>Search performed in: ' . $totalTime . ' seconds</h2>';

	}
?>